package com.chendx.store.seckill.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chendx.model.common.dtos.ResponseResult;
import com.chendx.model.common.enums.AppHttpCodeEnum;
import com.chendx.model.seckill.dto.SeckillOrderDto;
import com.chendx.model.seckill.pojo.SeckillGoods;
import com.chendx.model.seckill.pojo.SeckillOrder;
import com.chendx.model.seckill.vo.SeckillOrderVo;
import com.chendx.model.seckill.vo.SeckillStatus;
import com.chendx.model.user.pojo.User;
import com.chendx.store.common.constants.seckill.SeckillConstants;
import com.chendx.store.common.entity.IdWorker;
import com.chendx.store.seckill.mapper.SeckillGoodsMapper;
import com.chendx.store.seckill.mapper.SeckillOrderMapper;
import com.chendx.store.seckill.service.SeckillOrderService;
import com.chendx.store.seckill.thread.MultiThreadingCreateOrder;
import com.chendx.store.utils.AppThreadLocalUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

/**
 * Created by chendx on 2022/4/22.
 */
@Service
public class SeckillOrderServiceImpl extends ServiceImpl<SeckillOrderMapper, SeckillOrder> implements SeckillOrderService {

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;
    @Autowired
    private MultiThreadingCreateOrder multiThreadingCreateOrder;



    @Override
    public ResponseResult add(SeckillOrderDto dto) {
        User user = AppThreadLocalUtils.get();
        if (user == null || user.getId() == null || user.getUsername() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        Integer userId = user.getId();
        String userName = user.getUsername();
        try {
            if (dto == null || StringUtils.isEmpty(String.valueOf(dto.getSeckillId()))) {
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
            }
            if (StringUtils.isEmpty(dto.getReceiverAddress())
                    || StringUtils.isEmpty(dto.getReceiver())
                    || StringUtils.isEmpty(dto.getReceiverMobile())) {
                return ResponseResult.errorResult(AppHttpCodeEnum.RECEIVER_IS_ERROR);
            }
            if (StringUtils.isEmpty(dto.getUsername())){
                dto.setUsername(userName);
            }
            Object obj = redisTemplate.boundHashOps(SeckillConstants.SECKILL_GOODS_LIST + dto.getTime()).get(String.valueOf(dto.getSeckillId()));
            if (obj == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.SECKILL_GOODS_NO_EXIST);
            }
            //判断是否到时间抢购
            SeckillGoods seckillGoods = JSON.parseObject(obj.toString(), SeckillGoods.class);
            long startTimeSeconds = seckillGoods.getStartTime().getTime();
            long endTimeSeconds = seckillGoods.getEndTime().getTime();
            long nowTimeSeconds = System.currentTimeMillis();
            if (startTimeSeconds > nowTimeSeconds) {
                return ResponseResult.errorResult(AppHttpCodeEnum.NO_TIME_TO_SECKILL);
            }
            if (endTimeSeconds < nowTimeSeconds) {
                return ResponseResult.errorResult(AppHttpCodeEnum.END_SECKILLED);
            }
            //是否有库存
            Long stockCount = redisTemplate.boundListOps(SeckillConstants.SECKILL_GOODS_COUNT_LIST + dto.getSeckillId()).size();
            if (stockCount == null || stockCount <= 0) {
                return ResponseResult.errorResult(AppHttpCodeEnum.NO_STOCK_COUNT);
            }
            //抢单次数防止重复抢单
            long count = redisTemplate.boundHashOps(SeckillConstants.USER_QUEUE_COUNT).increment(dto.getUsername(), 1).longValue();
            if (count > 1) {
                return ResponseResult.errorResult(AppHttpCodeEnum.REPEAT_SECKILL);
            }
            //排队信息封装
            SeckillStatus seckillStatus = new SeckillStatus(dto.getUsername(), new Date(), "1", dto.getSeckillId(), dto.getTime());
            seckillStatus.setReceiver(dto.getReceiver());
            seckillStatus.setReceiverAddress(dto.getReceiverAddress());
            seckillStatus.setReceiverMoblie(dto.getReceiverMobile());
            //将排队信息存到redis中
            redisTemplate.boundListOps(SeckillConstants.SECKILL_ORDER_QUEUE).leftPush(JSON.toJSONString(seckillStatus));
            //将抢单状态存到redis中
            redisTemplate.boundHashOps(SeckillConstants.USER_QUEUE_STATUS).put(dto.getUsername(), JSON.toJSONString(seckillStatus));
            //多线程
            multiThreadingCreateOrder.createOrder();
            System.out.println("----其他程序正在执行-----");
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.okResult(AppHttpCodeEnum.SERVER_ERROR);
        }
    }

    @Override
    public ResponseResult queryStatus() {
        User user = AppThreadLocalUtils.get();
        if (user == null || user.getId() == null || user.getUsername() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        Integer userId = user.getId();
        String username = user.getUsername();
        Object o = redisTemplate.boundHashOps(SeckillConstants.USER_QUEUE_STATUS).get(username);
        if (o == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NOT_FOUND_ERROR);
        }
        SeckillStatus seckillStatus = JSON.parseObject(o.toString(), SeckillStatus.class);
        return ResponseResult.okResult(seckillStatus);
    }

    @Override
    public ResponseResult loadOrder(SeckillOrderDto dto) {
        User user = AppThreadLocalUtils.get();
        if (user == null || user.getId() == null || user.getUsername() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        Integer userId = user.getId();
        String username = user.getUsername();
        if (dto == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        LambdaQueryWrapper<SeckillOrder> queryWrapper = new LambdaQueryWrapper<>();
        if (!StringUtils.isEmpty(username)){
            queryWrapper.eq(SeckillOrder::getUserId,username);
        }
        if (!StringUtils.isEmpty(dto.getOrderStatus())){
            queryWrapper.eq(SeckillOrder::getOrderStatus,dto.getOrderStatus());
        }
        if (!StringUtils.isEmpty(dto.getPayStatus())){
            queryWrapper.eq(SeckillOrder::getPayStatus,dto.getPayStatus());
        }
        if (!StringUtils.isEmpty(dto.getConsignStatus())){
            queryWrapper.eq(SeckillOrder::getConsignStatus,dto.getConsignStatus());
        }
        queryWrapper.eq(SeckillOrder::getIsDelete,"0");
        List<SeckillOrder> list = list(queryWrapper);
        if (!StringUtils.isEmpty(dto.getPayStatus()) && dto.getPayStatus().equals("0")){
            SeckillOrder noPayOrder = JSON.parseObject((String) redisTemplate.boundHashOps(SeckillConstants.SECKILL_ORDER).get(username), SeckillOrder.class);
            if (noPayOrder != null){
                list.add(noPayOrder);
            }
        }
        List<SeckillOrderVo> voList = new ArrayList<>();
        for (SeckillOrder order : list){
            SeckillOrderVo vo = new SeckillOrderVo();
            BeanUtils.copyProperties(order,vo);
            vo.setId(String.valueOf(order.getId()));
            SeckillGoods seckillGoods = seckillGoodsMapper.selectById(order.getSeckillId());
            vo.setSeckillGoods(seckillGoods);
            voList.add(vo);
        }

        voList.sort(new Comparator<SeckillOrderVo>() {
            @Override
            public int compare(SeckillOrderVo o1, SeckillOrderVo o2) {
                return o2.getCreateTime().compareTo(o1.getCreateTime());
            }
        });
        return ResponseResult.okResult(voList);
    }

    /**
     * 关闭订单
     * @param username
     */
    @Override
    public void close(String username) {
        Object obj = redisTemplate.boundHashOps(SeckillConstants.SECKILL_ORDER).get(username);
        if (obj == null){
            return;
        }
        SeckillOrder seckillOrder = JSON.parseObject(obj.toString(),SeckillOrder.class);
        SeckillStatus seckillStatus = JSON.parseObject((String) redisTemplate.boundHashOps(SeckillConstants.USER_QUEUE_STATUS).get(username), SeckillStatus.class);
        if (seckillStatus != null && seckillOrder != null){
            //状态不为空
            //获取抢购商品id
            Object goodsObj = redisTemplate.boundHashOps(SeckillConstants.SECKILL_GOODS_LIST+seckillStatus.getTime()).get(String.valueOf(seckillStatus.getGoodsId()));
            if (goodsObj == null){
                return;
            }
            //删除订单中的用户信息
            redisTemplate.boundHashOps(SeckillConstants.SECKILL_ORDER).delete(username);
            SeckillGoods seckillGoods = JSON.parseObject(goodsObj.toString(), SeckillGoods.class);
            //库存回滚 +1
            Long stockCount = redisTemplate.boundHashOps(SeckillConstants.SECKILL_GOODS_COUNT).increment(String.valueOf(seckillGoods.getId()), 1);
            //库存队列 +1
            redisTemplate.boundListOps(SeckillConstants.SECKILL_GOODS_COUNT_LIST + seckillGoods.getId()).leftPush(String.valueOf(seckillGoods.getId()));
            //设置库存，数据库库存回滚
            if(seckillGoods != null){
                seckillGoods.setStockCount(stockCount.intValue());
                seckillGoodsMapper.updateById(seckillGoods);
            }
            seckillOrder.setPayStatus("3");
            seckillOrder.setOrderStatus("3");
            seckillOrder.setCloseTime(new Date());
            System.out.println("保存关闭订单到数据库");
            save(seckillOrder);
            //将数据同步到redis中
            redisTemplate.boundHashOps(SeckillConstants.SECKILL_GOODS_LIST + seckillStatus.getTime()).put(String.valueOf(seckillGoods.getId())
                    ,JSON.toJSONString(seckillGoods));
            //清理排队标示
            redisTemplate.boundHashOps(SeckillConstants.USER_QUEUE_COUNT).delete(username);
            //清理抢单标示
            redisTemplate.boundHashOps(SeckillConstants.USER_QUEUE_STATUS).delete(username);
        }
    }

    @Override
    public ResponseResult pay() {

        User user = AppThreadLocalUtils.get();
        if (user == null || user.getId() == null || user.getUsername() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        Integer userId = user.getId();
        String username = user.getUsername();
        Object obj = redisTemplate.boundHashOps(SeckillConstants.SECKILL_ORDER).get(username);
        if (obj == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NOT_FOUND_ERROR);
        }
        SeckillOrder seckillOrder = JSON.parseObject(obj.toString(), SeckillOrder.class);
        seckillOrder.setPayTime(new Date());
        seckillOrder.setStatus("1");
        seckillOrder.setPayStatus("1");
        seckillOrder.setConsignStatus("0");
        SeckillGoods seckillGoods = seckillGoodsMapper.selectById(seckillOrder.getSeckillId());
        if (seckillGoods == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.SECKILL_GOODS_NO_EXIST);
        }
        if (seckillGoods.getStockCount() != 0){
            seckillGoods.setStockCount(seckillGoods.getStockCount() - 1);
            seckillGoodsMapper.updateById(seckillGoods);
        }
        save(seckillOrder);
        //删除redis中的订单
        redisTemplate.boundHashOps(SeckillConstants.SECKILL_ORDER).delete(username);
        //删除用户排队信息
        redisTemplate.boundHashOps(SeckillConstants.USER_QUEUE_COUNT).delete(username);
        //清理排队存储信息
        redisTemplate.boundHashOps(SeckillConstants.USER_QUEUE_STATUS).delete(username);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Override
    public ResponseResult cancel() {
        User user = AppThreadLocalUtils.get();
        if (user == null || user.getId() == null || user.getUsername() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        String username = user.getUsername();
        redisTemplate.boundHashOps(SeckillConstants.USER_QUEUE_STATUS).delete(username);
        redisTemplate.boundHashOps(SeckillConstants.USER_QUEUE_COUNT).delete(username);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Override
    public ResponseResult one(String id) {
        User user = AppThreadLocalUtils.get();
        if (user == null || user.getId() == null || user.getUsername() == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        String name = user.getUsername();
        SeckillOrder seckillOrder = new SeckillOrder();
        SeckillOrderVo seckillOrderVo = new SeckillOrderVo();
        Object orderObj = redisTemplate.boundHashOps(SeckillConstants.SECKILL_ORDER).get(name);
        System.out.println("orderObj "+orderObj);
        if (orderObj == null){
            System.out.println("orderObj == null ");
            seckillOrder = getById(id);
            System.out.println(seckillOrder);
            if (seckillOrder == null){
                return ResponseResult.okResult(seckillOrderVo);
            }
        }else{
            System.out.println("orderObj != null ");
            System.out.println(seckillOrder);
            seckillOrder = JSON.parseObject(JSON.toJSONString(orderObj), SeckillOrder.class);
        }
        BeanUtils.copyProperties(seckillOrder,seckillOrderVo);
        SeckillGoods seckillGoods = seckillGoodsMapper.selectById(seckillOrder.getSeckillId());
        seckillOrderVo.setId(String.valueOf(seckillOrder.getId()));
        seckillOrderVo.setSeckillGoods(seckillGoods);
        return ResponseResult.okResult(seckillOrderVo);
    }

}
